

package com.googlecode.flac4j.format.frame.sub;


import com.googlecode.jinahya.io.BitInput;
import com.googlecode.jinahya.io.BitOutput;
import com.googlecode.jinahya.util.BitAccessible;

import java.io.IOException;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;


/**
 *
 * @author Jin Kwon <jinahya at gmail.com>
 */
@XmlType(propOrder = {"type", "wasted"})
public class SubHeader implements BitAccessible {


    @Override
    public void read(final BitInput input) throws IOException {

        type = input.readUnsignedInt(6);

        wasted = 0;
        if (input.readBoolean()) { // 1
            do {
                wasted++;
            } while (!input.readBoolean());
        }
    }


    @Override
    public void write(final BitOutput output) throws IOException {

        output.writeUnsignedInt(6, type);

        output.writeBoolean(wasted != 0);
        if (wasted != 0) {
            output.writeUnsignedInt(wasted, 0x01);
        }
    }


    // --------------------------------------------------------- parent Subframe
    /**
     * Returns parent SubFrame of this SubData.
     *
     * @return parent SubFrame
     */
    public final SubFrame getSubFrame() {
        return subFrame;
    }


    /**
     * Sets the parent SubFrame of this SubData.
     *
     * @param subFrame parent SubFrame
     */
    public final void setSubFrame(final SubFrame subFrame) {

        if (subFrame == null) {
            throw new NullPointerException("null subFrame");
        }

        this.subFrame = subFrame;
    }


    // -------------------------------------------------------------------- type
    /**
     * Returns the type of this SubFrame.
     *
     * @return the type of this SubFrame.
     */
    public int getType() {
        return type;
    }


    /**
     * Sets the type of this SubFrame.
     *
     * @param type the type of this SubFrame.
     */
    public void setType(final int type) {

        if (type >> 6 != 0) {
            throw new IllegalArgumentException("type(" + type + ") >> 6 != 0");
        }

        this.type = type;
    }


    public int getOrder() {
        if (type >= 0x08 && type <= 0x0F) { // 001xxx
            return type & 0x07;
        } else if (type >= 0x20 & type <= 0x3F) { // 1xxxxx
            return (type & 0x1F) + 1;
        }

        return 0;
    }


    // ------------------------------------------------------------------ wasted
    /**
     * Returns the 'wasted bits-per-sample'.
     *
     * @return wasted bits-per-sample.
     */
    public int getWasted() {
        return wasted;
    }


    /**
     * Sets the 'wasted bits-per-sample'.
     *
     * @param wasted wasted bits-per-sample
     */
    public void setWasted(final int wasted) {

        if (wasted < 0) {
            throw new IllegalArgumentException("wasted(" + wasted + ") < 0");
        }

        this.wasted = wasted;
    }


    /** parent SubFrame. */
    @XmlTransient
    private SubFrame subFrame;


    /** SubFrame type. */
    @XmlElement(required = true)
    private int type;


    /** wasted bits-per-sample. */
    @XmlElement(required = true)
    private int wasted = 0;


}

